數據結構之線性表數組表達c++版本(一)

本例子是《數據結構與算法c++描述》中的線性表中抽象數據類型 (abstract data type, ADT):

目錄

基本概念:

構造函數與析構函數:

是否爲空:

Find函數:

查找函數:

刪除數據:

插入函數:

輸出函數與重構 << 符號輸出:

題目部分函數:

changeSize函數:

Reverse函數:

複製構造函數:

操作函數:

線性交叉函數:

Merge函數:

Split函數:

測試程序:


基本概念:

先看基本類型吧:

      本例子採用了類模板,這裏提醒一下大家,不要把定義與實現一個寫在.h與.cpp, 因爲模板的性質,當你在別的文件使用的時候,就會報無法解析外部符號的錯誤。

      本例子代碼是書上的代碼,後邊的新加的功能是課後習題需要開發的,同時也對這個程序完善了一部分。

首先我們先看類的定義:

listearLine.h 文件中

/*
數組結構中的線性表數組樣式

對應書中代碼:數據結構算法與應用c++描述

程序編寫:比卡丘不皮

編寫時間:2020年6月24日 13:51:23

*/
#pragma once
#include <iostream>
#include "all_error.h"
#include <time.h>
using namespace std;

template<class T>
class LinearList
{
public:
	LinearList();
	LinearList(int MaxListSize ); //構造函數默認爲
	~LinearList();                    //析構函數
	LinearList(const LinearList<T> & L);  //複製構造函數
	bool IsEmpty()const;              //判斷是否爲空
	int Length() const { return length; }  //返回表的長度,即表中元素個數 
	bool Find(int k, T& x)const; //返回第k個元素至x中 若不存在第k個元素,則返回false
	int Search(const T& x) const; // 返回x所在位置 如果x 不在表中,則返回0
	LinearList<T>& Delete(int k, T& x); // 刪除第k個元素並將它返回至x中
	LinearList<T>& Insert(int k, const T& x); // 在第k個元素之後插入x
	//改變數組最大長度函數,l爲數組長度,m爲數組最大長度
	LinearList<T>& changeSize(T * elementNew, int nlength, int max); 
	LinearList<T>& Reverse();  //元素次序的反轉 element[k]=element[length-k]
	LinearList<T>& Half();  //數組減半
	void Reset() { current = 1; } //設置數據位
	bool Current(T &x);     //返回當前的值
	bool End()const;       //是否爲最後邊
	bool Front() const;   //是否爲最前邊
	void Next();        //到下個值
	void Previous();    //到前一個值
	void clear();
	//線性表交叉組合
	LinearList<T>& Alternate(const LinearList<T> & list1, const LinearList<T> & list2);
	//有規律(元素從小到大排列)線性表的組合
	LinearList<T>& Merge(const LinearList<T> & list1, const LinearList<T> & list2);
	//線性表分割函數
	void Split(LinearList<T> & list1, LinearList<T> & list2);

	void Output(ostream& out) const; // 輸出函數
	LinearList<T> & operator =(const LinearList<T> & x); //重載賦值運算
private:
	int length;   //數組的長度
	int MaxSize;  //數組最大值
	T * element; //一維動態數組
	int current;  //元素當前的位置
};

這裏先講下 

#include "all_error.h"

這裏我寫了拋出的異常類:

/*
線性表中的數組結構

對應書中代碼:數據結構算法與應用c++描述

程序編寫:比卡丘不皮

編寫時間:2020年6月24日 13:51:23

*/
#pragma once

#include <iostream>
using namespace std;

class Noman
{
public:
	Noman()
	{
		cout << "內存不足"<< endl;
	}
	~Noman()
	{

	}
};

//使new引發NoMemory異常而不是xalloc異常

void my_new_handler()
{
	throw Noman();
}

new_handler Old_Handler_ = set_new_handler(my_new_handler);

class OutOfBounds
{
public:
	OutOfBounds()
	{
		cout << "超出範圍" << endl;
	}
	~OutOfBounds()
	{

	}
};


爲了超出數組觸發不同的異常警告。

還是回到類成員函數中(listearLine.h 裏面): 

構造函數與析構函數:

template<class T>
inline LinearList<T>::LinearList()
{
	MaxSize = 1;
	element = new T[MaxSize];
	length = 0;
}

//構造函數默認爲10
template<class T>
LinearList<T>::LinearList(int MaxListSize)
{
	MaxSize = MaxListSize;
	element = new T[MaxSize];
	length = 0;
}

//析構函數
template<class T>
LinearList<T>::~LinearList()
{
	delete[] element;  
}

是否爲空:

//判斷是否爲空
template<class T>
bool LinearList<T>::IsEmpty() const
{
	return 0 == length;
}

Find函數:

//返回第k個元素至x中 若不存在第k個元素,則返回false
template<class T>
bool LinearList<T>::Find(int k, T & x) const
{
	if (k<1 || k>length)
	{
		return false;
	}
	else
	{
		x = element[k-1];
	}

	return true;
}

查找函數:

template<class T>
int LinearList<T>::Search(const T & x) const
{
	for (int i =0; i<length; i++)
	{
		if (x == element[i])
		{
			return ++i;
		}
	}
	return 0;
}

刪除數據:

template<class T>
LinearList<T>& LinearList<T>::Delete(int k, T & x)
{

	if (Find(k,x))
	{
		for (int i = k; i < length; i++)
		{
			element[i - 1] = element[i];
		}
		length--;
		if (length == (MaxSize / 4) && length > 0)
		{
			MaxSize /= 2;
			changeSize(element,length,MaxSize);
		}
		
		return *this;
	}
	else
	{
		throw  OutOfBounds();
	}
}

這裏本沒有:

if (length == (MaxSize / 4) && length > 0)
		{
			MaxSize /= 2;
			changeSize(element,length,MaxSize);
		}

這段代碼,這裏是後面習題中添加的功能,後面又詳細解答。

插入函數:

//插入數據
//在第k個元素之後插入x;函數返回修改後的線性表
template<class T>
LinearList<T>& LinearList<T>::Insert(int k, const T & x)
{
	//在第k個元素之後插入x;函數返回修改後的線性表
	//如果不存在第k個元素,則引發異常OutOfBound
	//如果表已經滿,則引發異常NoMem
	if (k<0 || k > length)
	{
		throw OutOfBounds();
	}
	if (length == MaxSize)
	{
		throw Noman();
	}
	//向後移動一位 書中這裏是減一 書寫錯誤
	for (int i = length - 1; i >= k; i--)
	{
		element[i + 1] = element[i];
	}
	element[k] = x;
	length++;
	if (length == MaxSize)
	{
		MaxSize *= 2;
		changeSize(element, length, MaxSize);
	}

	return *this;
}

輸出函數與重構 << 符號輸出:

template<class T>
void LinearList<T>::Output(ostream & out) const
{
	for (int i = 0; i < length; i++)
	{
		out << element[i] << " ";
	}
}

template<class T>
ostream & operator<<(ostream & out, const LinearList<T> & x)
{
	x.Output(out);
	return out;
}

已上的函數功能都是書中的代碼部分,下面的部分爲書上 課後習題裏面需要的。

題目部分函數:

changeSize函數:

//改變大小,節省空間
template<class T>
inline LinearList<T>& LinearList<T>::changeSize(T * elementNew, int nlength, int max)
{
	element = new T[max];
	for (int i = 0; i<nlength; i++)
	{
		element[i] = elementNew[i];
	}
	delete[] elementNew;
	return *this;
}

       這個函數可以節省空間,可以看插入函數與刪除函數,在執行刪除操作期間,如果線性表的尺寸降至當前 MaxSize 的四分之一,則分配一個更小的、尺寸爲 MaxSize / 2的數組,並將老數組中的數據複製到新數組中,最後將老數組刪除。

題目2:

Reverse函數:

//數據反轉函數
template<class T>
 LinearList<T>& LinearList<T>::Reverse()
{
	for (int i = 0; i< (length/2); i++)
	{
		T temp = element[i];
		element[i] = element[length-1-i];
		element[length - 1 - i] = temp;
	}
	return *this;

}

//就地反轉函數利用對象
template<class T>
void ReverseEle(LinearList<T> & data)
{
	data.Reverse();
}

這裏是後面對比使用的函數。


 

 template<class T>
 LinearList<T>& LinearList<T>::Half()
 {
	 length = (length + 1) / 2;
	 //這裏兩種方案來寫程序,也是劍指offer中的知識點  
	 //方法1
	 T *elementNew = new T[length+1];
	 for (int i = 0; i<=length; i++)
	 {
		 elementNew[i] = element[2 * i];
	 }
	 delete[] element;

	 element = new T[length+1];
	 for (int i = 0; i <= length; i++)
	 {
		 element[i] = elementNew[i];
	 }

	 delete[] elementNew;
	 return *this;
	 //方法二是直接利用構造函數,這樣就不用自己寫delete了,這裏就不記錄了
 }

 複製構造函數:

//複製構造函數
template<class T>
 LinearList<T>::LinearList(const LinearList<T>& L)
{
	if (this == &L)
	{
		return;
	}
	else
	{
		this->length = L.length;
		this->MaxSize = L.MaxSize;
		delete[] element;
		element = new T[length+1];
		memcpy(element, L.element, length * sizeof(T));

	}
}

當寫完後一定要寫重載 = 符號不然很容易出問題:

template<class T>
inline LinearList<T>& LinearList<T>::operator=(const LinearList<T>& x)
{
	if (this == &x)
	{
		return *this;
	}
	this->MaxSize = x.MaxSize;
	this->length = x.length;
	memcpy(element, x.element,length * sizeof(T));
}

操作函數:

template<class T>
 bool LinearList<T>::Current(T & x)
 {
	 if (current < 0 || current > MaxSize)
	 {
		 return false;
	 }
	 else
	 {
		 x = element[current - 1];
		 return true;
	 }

 }

 template<class T>
 inline bool LinearList<T>::End() const
 {
	 return current == length;
 }

 template<class T>
 inline bool LinearList<T>::Front() const
 {
	 return current == 1;
 }

 template<class T>
 inline void LinearList<T>::Next()
 {
	 if (current < length)
	 {
		 current++;
	 }
	 else
	 {
		 throw OutOfBounds();
	 }
 }

 template<class T>
 inline void LinearList<T>::Previous()
 {
	 if (current > 1)
	 {
		 current--;
	 }
	 else
	 {
		 throw OutOfBounds();
	 }
 }

 template<class T>
  void LinearList<T>::clear()
 {
	  this->MaxSize = 1;
	  delete [] element;
	  element = new T[MaxSize];
	  this->length = 0;
 }

Reset 在定義的時候已經寫完了。這裏我自己添加了個clear函數。

線性交叉函數:

template<class T>
 LinearList<T>& LinearList<T>::Alternate(const LinearList<T>& list1, const LinearList<T>& list2)
 {
	 //線性交叉 
	 if (length>0)
	 {
		 delete[] element; //清除原有數據
	 }
	 length = list1.length + list2.length;
	 element = new T[length]; 
//	 MaxSize = length;
	 LinearList<T> A = list1, B = list2; //複製構造函數
	 A.Reset();
	 B.Reset();
	 int value = 0; //記錄當前位置的值
	 int minLenght = A.length <= B.length ? A.length: B.length; //獲取當前比較小的值

	 for (int i = 0; i<minLenght;i++)
	 {
		 if (A.Current(value))
		 {
			 element[2 * i] = value;
		 }
		 
		 if (B.Current(value))
		 {
			 element[2 * i + 1] = value;
		 }
		 if (A.End() || B.End())  //判斷當前是否爲最後一個
		 {
			 break;
		 }
		 else
		 {
			 A.Next();
			 B.Next();
		 }
	 }

	 for (int i = 2 * minLenght; i<length; i++ )
	 {
		 //判斷不是結尾
		 if (!A.End())
		 {
			 A.Next();
			 A.Current(value);
			 element[i] = value;
		 }
		 else
		 {
			 B.Next();
			 B.Current(value);
			 element[i] = value;
		 }
	 }

	 return *this;

 }

 Merge函數:

template<class T>
 LinearList<T>& LinearList<T>::Merge(const LinearList<T>& list1, const LinearList<T>& list2)
 { 
	 if (length > 0)
	 {
		 delete[] element;
	 }
	 length = list1.length + list2.length;
	 MaxSize = length;
	 element = new T[length]; //創建新的標籤

	 int ca = 0, cb = 0, ct = 0;
	 //先拍都有的數據
	 while (ca < list1.length && cb < list2.length)
	 {
		 if (list1.element[ca] >= list2.element[cb])
		 {
			 element[ct++] = list2.element[cb++];
		 }
		 else
			 element[ct++] = list1.element[ca++];
	 }
	 //在排剩下的數據
	 if (ca == list1.length) //表示list1數組排完了
	 {
		 for (int i = cb;i < list2.length;i++)
		 {
			 element[ct] = list2.element[i];
			 ct++;
		 }
	 }
	 else
	 {
		 for (int i = ca; i < list1.length; i++)
		 {
			 element[ct] = list1.element[i];
			 ct++;
		 }
	 }
	 return *this;
 }

Split函數:

 void LinearList<T>::Split(LinearList<T>& list1, LinearList<T>& list2)
 {
	 int aNum = 0;
	 int bNum = 0;
	 for (int i = 0; i < length; i++)
	 {
		 if ((i & 1) == 0)
		 {
			 list1.Insert(aNum++, element[i]);
		 }
		 else
		 {
			 list2.Insert(bNum++, element[i]);
		 }
	 }
 }

   測試程序:

//測試列表數組
void testLinearList()
{
	try
	{
		//設置爲空的時候
		cout << "初始化開始" << endl;
		LinearList<int> L;
		cout << "Lenght = " << L.Length() << endl;
		cout << "IsEmpty = " << L.IsEmpty() << endl;

		L.Insert(0, 2);
		L.Insert(1, 6);
		//也可以這樣寫
		L.Insert(2, 5).Insert(3, 4).Insert(4, 8);
		cout << "List is " << L << endl;
		cout << "isEmpty " << L.IsEmpty() << endl;

		//測試插入函數
		L.Insert(1, 10).Insert(2,1);
		cout << "List is " << L << endl;
		cout << "isEmpty " << L.IsEmpty() << endl;
		cout << "lengh is " << L.Length()<< endl;
		int z;
		L.Find(1, z); //找到第一個數的數據
		cout << "first element " << z << endl;
		cout << "Lenght = " << L.Length() << endl;
		cout << "lengh is " << L.Length() << endl;

		L.Delete(1, z);
		cout << "Deleted element is " << z << endl;
		cout << "List is " << L << endl;
		cout << "lengh is " << L.Length() << endl;

		cout << endl;
		//測試查找
		cout << "test Search" << endl;
		cout << "List is " << L << endl;
		cout << "6 in L? " << L.Search(6) << endl;
		cout << "9 in L? " << L.Search(9) << endl;

		cout << endl;
		cout << "test Reverse" << endl;
		L.Reverse();
		cout << "List is " << L << endl;
		cout << "isEmpty " << L.IsEmpty() << endl;
		cout << "lengh is " << L.Length() << endl;
		
		//反轉測試
		for (int i = 0; i<500000; i++)
		{
			L.Insert(i, i);
		}
		cout << L.Length() << endl;
		clock_t  startTime, stopTime;
		startTime = clock();
		L.Reverse();
		stopTime = clock();

		cout << "類成員反轉使用的時間: " << float(stopTime - startTime) / CLK_TCK << endl;

		//就地反轉
		startTime = clock();
		ReverseEle(L);
		stopTime = clock();
		cout << "就地反轉使用的時間: " << float(stopTime - startTime) / CLK_TCK << endl;

		//測試half
		L.Half();
		cout << "length is : " << L.Length()<< endl;

		//測試複製構造函數
		LinearList<int> ML(L);
		cout << "length L is : " << L.Length() << endl;
		cout << "length ML is : " << ML.Length() << endl;

		//測試current類容
		ML.Reset(); //位置置0

		//測試next
		ML.Next(); //移動到下個位置
		cout << "判斷是否是前邊的 " << ML.Front() << endl;
		int value = 0;
		cout << "當前是否有問題 :" << ML.Current(value) << endl;
		cout << "輸出當前的值是 :" << value << endl;
		//其他函數測試也是相同的

		//測試交叉數據
		LinearList<int> A, B;
		for (int i = 0; i<4; i++)
		{
			A.Insert(i, i);
			B.Insert(i, i);
		}
		B.Insert(4, 4).Insert(5, 5);
		cout << "A is List : " << A <<endl;
		cout << "B is List : " << B <<endl;
		LinearList<int> C;
		C.Alternate(A,B);
		cout << "C is list :" << C << endl;
		//測試合併排序,前提都是順序的
		A.Insert(4, 10);
		LinearList<int> D;
		D.Merge(A,B);
		cout << "D is list :" << D << endl;

		//測試
		A.clear();
		B.clear();
		D.Split(A,B);
		cout << "D is list :" << D << endl;
		cout << "A is List : " << A << endl;
		cout << "B is List : " << B << endl;


	}
	catch (const std::exception&)
	{
		cerr << "An exception has occurred" << endl;
	}
}

 主函數:

#include <iostream>
#include "listearLine.h"
using namespace std;

int main()
{
	//測試線性表數組
	testLinearList();
	return 0;
}

      已上就是題目中的程序了,從第9題目開始,只是變成下標爲1開始數組,這裏類推一下就好不難的。寫題目部分程序畢竟是自己來寫的,難免會有程序問題,若你有發現問題,可在下面評論區交流,或者關注我博客,讓我們一起進步,加油。

需要書籍的可以來取:

         對應數據結構的書籍

本文例子的連接:

 鏈接:本文例子  提取碼:ao3c

如果例子失效,可以私信,或者下方評論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章