1. 程式人生 > >線性表C++實現(20180302)

線性表C++實現(20180302)

參考 https://www.cnblogs.com/ruanjianxiaosheng/p/4028419.html

學習分三點:

1.資料描述

2.資料儲存

3.資料操作

1、資料描述

線性表的資料元素具有抽象(及不確定)的資料型別,只有在設計具體的應用程式時,資料元素的抽象型別將被具體的資料型別所取代,比如:字元型(char)、整型(int)、結構體型別(struct)等等。


資料儲存線上性表裡有兩種:一是順序儲存結構,簡稱順序表。二是鏈式儲存結構,簡稱連結串列。(

   (順序表是在計算機記憶體中以陣列的形式儲存的線性表)

  • 順序表是用一段地址連續的儲存單元依次儲存線性表的資料元素。因為順序表中資料元素的儲存地址是其序號的線性函式,只要確定了儲存順序表的起始地址(即基地址),計算任何一個元素的儲存地址的時間是相等的,所以它的
  •     優點是:隨機存取(即按下標可以隨機訪問順序表中任何一個數據元素,時間開銷小。O(1))。但也因為順序表利用陣列元素在物理位置(及陣列下標)上的鄰接關係來表示線性表中資料元素之間的邏輯關係,這使得順序表具有以下
  •     缺點

          (1)表的容量難以確定。陣列的長度必須事先確定。

          (2)插入和刪除操作需要移動大量元素。

          (3)造成儲存空間的“碎片”。這是因為陣列要求佔用連續的儲存空間,即使儲存單元數超過所需的數目,如果不連續便無法使用,這便造成了儲存空間“碎片”現象。

  • 連結串列是為了克服順序表的的缺點,採用的動態儲存分配來儲存線性表。需要時可以用new分配記憶體空間,不需要時用delete將已分配的空間釋放,不會造成記憶體空間的浪費。而且插入刪除操作也非常方便。唯一的缺點就是
    訪問連結串列中的節點不是很方便。連結串列中的節點,需從頭指標順著連結串列掃描才能取得。

什麼是資料域和指標域?

資料域儲存需要的資料,而指標域存放下個節點的位置。

如果用連結串列儲存,則要在上面程式碼新增

StuGrade *next;//指標域

   (順序表是在計算機記憶體中以陣列的形式儲存的線性表)

3、資料操作

無論線性表用哪種方式儲存,最終還是為了資料處理方便。線上性表中,資料處理包括初始化、查詢、插入、刪除、遍歷等等。用類封裝起來就是:

   (順序表是在計算機記憶體中以陣列的形式儲存的線性表)

用陣列方式


#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <string>
using namespace std;


struct StuGrade {
	string num;
	string name;
	char sex;
	float Math, Eng, Comp;
};


const int MaxSize = 10;
class SeqList
{
public:
	SeqList();                     //無參建構函式,建立一個空的順序表
	SeqList(StuGrade a[], int n);  //有參建構函式,建立一個長度為n順序表
	~SeqList() {}
	int Length();                  //求線性表的長度
	StuGrade Get(int i);           //按位查詢
	int Locate(StuGrade x);		   //按值查詢
	void Insert(int i, StuGrade x);//插入操作
	void Delete(int i);            //刪除操作
	void PrintList();              //遍歷操作

private:
	StuGrade data[MaxSize];
	int length;
};

SeqList::SeqList(StuGrade a[], int n)
{
	if (n > MaxSize) throw int(1);
	for (int i = 0; i < n; i++)
		data[i] = a[i];
	length = n;

}

void SeqList::Insert(int i,StuGrade x)
{
	char a;
	if (length >= MaxSize)
	{
		throw a;

	}
	if (i<1 || i>length + 1)
	{
		throw float(0.5);

	}
	for (int j = length; j >= i; j--)
		data[j] = data[j - 1];
	
	data[i - 1] = x;
	
	length++;

}

void SeqList::Delete(int i)
{
	if (length == 0)throw double(0.55);
	if (i<1 || i>length)throw float(0.5);
	for (int j = i; j < length; j++)
		data[j - 1] = data[j];
	length--;
}

void SeqList::PrintList()
{
	for (int i = 0; i < length; i++)
		cout << data[i].num << '\t' << data[i].name << '\t' << data[i].sex << '\t' << data[i].Math <<
		'\t' << data[i].Eng << '\t' << data[i].Comp << endl;
}


int main()
{
	StuGrade stu[2];
	for (int i = 0; i < 2; i++)
	{
		cout << "請輸入第" << i + 1 << "位學生學號:" << endl;
		cin >> stu[i].num;
		cout << "請輸入該學生姓名:" << endl;
		cin >> stu[i].name;
		cout << "請輸入該學生性別:" << endl;
		cin >> stu[i].sex;
		cout << "請輸入該學生數學成績:" << endl;
		cin >> stu[i].Math;
		cout << "請輸入該學生英語成績" << endl;
		cin >> stu[i].Eng;
		cout << "請輸入該學生計算機成績" << endl;
		cin >> stu[i].Comp;
	}
	SeqList Grade(stu, 2);
	try {
		Grade.Insert(2, stu[0]);
		Grade.Delete(1);
		Grade.PrintList();
	}
	catch (int) { cout << "引數非法" << endl; }
	catch (char) { cout << "上溢" << endl; }
	catch (float) { cout << "刪除位置不當" << endl; }
	catch (double) { cout << "下溢" << endl; }
	return 0;

}
	

可以在刪除和插入元素的函式中看到,要移動大量元素,十分不靈活。

鏈式表實現:

// 鏈式表.cpp: 定義控制檯應用程式的入口點。
// 鏈式表的元素訪問比較複雜,因為指標必須從頭開始遍歷到所尋找元素的位置。

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


typedef struct LNode *List;
struct LNode {
	double list;
	List Next;

};

struct Lnode L;
List PtrL;

//查表長
int Length(List PtrL)    //通過遍歷
{
	List p = PtrL;       //臨時指標p,指向表的第一個結點//
	int j = 0;
	while (p) {          //迴圈條件是p指標不等於0
		p = p->Next;
		j++;             //當前p指向的是第j個結點//
	}
	return j;
}
//時間複雜度為O(n)


//按序號查詢
List FindKth(int K, List PtrL)
{
	List p = PtrL;
	int i = 1;
	while (p != NULL && i < K)
	{
		p = p->Next;   //往後挪一個node
		i++;
	}
	if (i == K)
		return p;     //找到第K個,返回指標//
	else
		return NULL;

}

//按數值尋找,返回該數值的指標

List Find(double X, List PtrL)
{
	List p = PtrL;
	while (p != NULL && p->list != X)
	{
		p = p->Next;
	}
	return p;
}

//插入
//(1)先構造一個新節點,用s指向;
//(2)再找到連結串列的第i-1個結點,用p指向;
//(3)然後修改指標,插入結點(p之後的新結點是s)

//1.s->Next = p->Next;
//2.p->Next = s;


List Insert(double X, int i, List Ptrl)
{
	List p, s;     //構建兩個指標
	if (i == 1) {
		s = (List)malloc(sizeof(struct LNode));
		s->list = X;
		s->Next = PtrL;
		return s;
	}
	p = FindKth(i - 1, PtrL);   //查詢i-1結點在哪裡//
	if (p == NULL)
	{
		cout << "引數i錯";
		return NULL;

	}
	else
	{
		s = (List)malloc(sizeof(struct LNode));  //申請,填裝結點
		s->list = X;
		s->Next = p->Next;                       //新結點插入在第i-1個結點後面
		p->Next = s;
		return PtrL;
	}
}


//刪除
//(1)先找到連結串列的第i-1個結點,用p指向;
//(2)再用指標s指向要被刪除的結點(p的下一個結點);
//(3)然後修改指標,刪除s所指結點;
//(4)釋放s所指結點的空間


List Delete(int i, List PtrL)
{
	List p, s;
	if (i == 1)
	{
		s = PtrL;
		if (PtrL != NULL)
			PtrL = PtrL->Next;
		else
			return NULL;
		
		free(s);
		
		return PtrL;
	}
	p = FindKth(i - 1, PtrL);
	if (p == NULL)
	{

		return NULL;
	}
	else if (p->Next == NULL)
	{
		return NULL;
	}

	else
	{
		s = p->Next;
		p->Next = s->Next;
		free(s);  //要釋放被刪除的結點
		return PtrL;
	}

}