線性表C++實現(20180302)
阿新 • • 發佈:2019-02-02
參考 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;
}
}