一、線性表的定義
線性表:零個或多個數據元素的有限序列
- 元素之間是有順序的。
- 第一個元素無前驅,最後一個元素無後驅,其他的每一個元素有且只有一個前驅和後驅。
- 線性表元素的個數n定義爲線性表的長度,n=0,空表。
二、線性表的抽象數據類型
線性表的抽象數據類型定義如下:
/****抽象數據類型定義******/
InitList(*L); //初始化操作,建立一個空的線性表L
ListEmpty(L); //若線性表爲空,返回true,否則返回false
ClearList(*L); //將線性表清空
GetElem(L,i,*e); //將線性表L中的第i個元素值返回給e
LocateElem(L,e); //查找成功放回序號,查找失敗返回0
ListInsert(*L,i,e) //在線性表L的第i個位置插入e
ListDelet(*L,i,*e) //刪除第i個位置元素,並用e返回其值
ListLength(L); //返回線性表的元素個數
三、線性表的順序存儲結構
1.順序存儲定義:用一段地址連續的存儲單元依次存儲線性表的數據元素。
2.順序存儲方式:C語言的一維數組
/*********順序存儲的結構代碼**********/
#define MAXSIZE 20 //存儲空間初始分配量
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];
int length;
} SqList;
順序存儲結構需要三個屬性:
- 存儲空間的起始位置:數組data
- 線性表的最大存儲容量:數組長度MAXSIZE
- 線性表的當前長度:length3.
3.數據長度與線性表長度
- 數據長度:存儲的空間長度(MAXSIZE)
- 線性表長度:元素個數(length)
4.地址的計算辦法
存儲器中的每個存儲單元都有自己的編號,這個編號稱爲地址。
四、順序存儲結構的插入與刪除
- 獲得元素操作
- 插入操作
- 刪除操作
/**********獲得元素的操作******************/
#define OK 1
#define ERROR 0
Statues GetElem(SqList L, int i, ElemType *e)
{
if(L.length==0||i<1||i>L.length)
return ERROR;
*e=L.data[i-1];
return OK;
}
/***************順序存儲結構的插入**********************/
Status ListInsert(SqList *L,int i,ElemType)
{
int k;
if(L->length>MAXSIZE) //線性表已滿
return ERROR;
if( i<1 || i>L->length ) //i的位置不對
return ERROR;
if( i <= L->length)
{
for(k=L->length-1; k>=i-1; k--) //將插入位置後的元素向後移動一位
{
L->data[k+1] = L->data[k];
}
}
L->data[i-1]=e;
L->length++;
}
/******************順序存儲結構的刪除*************/
Status ListDelete(SqList *L,int i, ElemType)
{
int k;
if(L->length==0) //線性表爲空
return ERROR;
if( i<1 || i>L->length ) //i的位置不對
return ERROR;
*e = L->data[i-1]
if( i <= L->length)
{
for(k=i; k<L->length; k--) //將插入位置後的元素向後移動一位
{
L->data[k-1] = L->data[k];
}
}
return OK;
}
五、線性表的鏈式存儲結構
- 順序存儲結構的不足:插入和刪除時需要移動大量的元素
- 線性表的鏈式存儲結構的定義
結點:
鏈表:n個結點鏈結成一個鏈表
單鏈表:鏈表中的每個結點只包含一個指針域
頭指針:鏈表中的第一個結點的存儲位置
頭結點:在單鏈表的第一個結點前附設一個結點,稱爲頭結點 - 頭指針和頭結點的異同
頭指針:指向鏈表第一個結點的指針,若鏈表有頭結點,則是指向頭結點的指針。頭指針是鏈表的必要的元素
頭結點:放在第一個元素之前的結點,頭結點不是鏈表的必須要素 - 線性錶鏈式存儲結構代碼描述
/***************線性表的單鏈表存儲結構*****************/
typedef struct Node
{
ElemType data;
struct Node *next;
} Node;
typedef struct Node *LinkList;
鏈接由結點構成
結點由存放數據的元素的數據域和存放後繼結點地址的指針域組成
六、單鏈表的讀取
獲取單鏈表的第i個數據
- 聲明一個指針p指向單鏈表的第一給結點 j=1;
- j<i時,遍歷鏈表,讓p指針向後移動,不斷的指向下一個結點,j++;
- 若到單鏈表的尾部,則說明i 點不存在;
- 否則查找成功,返回結點p的數據、
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p; //聲明一個指針p
p = L->next; //p指向鏈表L的第一個結點
j = 1;
while( p && j<i ) //p不爲空 且 j<i
{
p = p->next;
j++;
}
if(!p || j>i)
return -1;
*e = p->data;
return 0;
}
七、單鏈表的插入與刪除
- 單鏈表的插入
先把p的後繼結點改成s的後繼結點
在把s變成p的後繼結點
(順序不可以變)
/**********************單鏈表的插入(單鏈表第i個數據插入結點)*************************/
/*
1.聲明一指針p指向鏈表的頭結點,同時 j = 1
2.當 j < i 時,遍歷鏈表,讓p指針向後移動,不斷指向下一個結點, p++
3.若到鏈表的末尾p爲空,則說明第i個結點不存在
4.否則查找成功,在系統中生成一個空節點s
5.將元素e賦值給s->data
6.單鏈表的插入標準語句 s->next = p->next p->next = s
7.返回成功
*/
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p = *L; //指針指向鏈表l
j = 1;
while( p && j < i )
{
p = p->next;
j++;
}
if(!P || j < i)
return -1;
s = (LinkList)malloc(sizeof(Node)) ; //生成新結點
s->data = e;
s->next = p->next;
p->next = s;
return 0;
}
- 單鏈表的刪除
只需要一步:p->next = p->next->next
/******************單鏈表的刪除***************/
/*
1.聲明一個指針p指向鏈表頭指針, j = 1
2.當 i < j時,就遍歷鏈表,讓p指針向後移動,不斷的指向下一個結點, j++
3.若到鏈表尾部p爲空,則說明i結點不存在
4.否則查找成功,將欲刪除的結點 p->next賦值給q
5.單鏈表的刪除標準語句 p->next = q->next
6.將q結點中的數據賦值給e,作爲返回
7.釋放q結點
8.返回成功
*/
Status ListDelete(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,q;
j = 1;
while(p->next && j < i)
{
p = p->next;
j++;
}
if( !(p->next) || j > i )
return -1;
q = p->next;
p->next = q->next;
*e = q->data;
free(q); //釋放結點q
return 0;
}
八、單鏈表整表的建立
單鏈表的建立就是一個動態生成鏈表的過程;從‘空表‘的初始狀態起,依次建立各元素結點,並逐個插入鏈表。
單鏈表整表的建立有兩種方法:頭插法,尾插法
/*********單鏈表整表創建的算法:頭插法********************/
/*
1.聲明一個 指針p 和 計數變量 i;
2.初始化一個空鏈表L;
3.讓L的頭結點的指針指向空,即建立一個帶頭結點的單鏈表;
4.循環:
生產一個新節點賦值給p;
生成一個新節點賦值給p的數據域 p->data;
將p插入到頭結點與前一個新結點之間;
*/
void CreatListHead(LinkList *L,int n)
{
LinkList p; //聲明指針 p
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL; //創建一個帶頭結點的鏈表L
for( i = 0; i < n; i++)
{
p = (LinkList) malloc (sizeof(Node)); //生成新結點
p->data = rand()%100 + 1;
p->next = (*L)->next; //查入到表頭
}
}
/*********單鏈表整表創建的算法:尾插法********************/
void CreatListTail(LinkList *L,int n)
{
LinkList p,r;;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node)); //爲整個線性表
r = L;
for( i = 0; i < n; i++)
{
p = (Node *)malloc(sizeof(Node)); //生成新結點
p->data = rand()%100+1;
r->next = p; //將表尾終端結點的指針指向新結點
r = p; //新結點變成尾結點
}
r->next = NULL; //表示當前鏈表結束
}
九、單鏈表整表的刪除
/*********************單鏈表的刪除 ************************/
/*
1.聲明一個結點p和q;
2.將第一個結點賦值給p;
3.循環:
將下一個結點賦值給q;
釋放p;
將q賦值給p;
*/
Status ClearList(LinkList *L)
{
LinkList p,q;
p = (*L)->next; //p指向第一個結點
while(p) //沒到表尾
{
q = p->next;
free(q);
p = q;
}
(*L)->next =NULL;
return 0;
}
十、靜態鏈表
- 定義:用數組描述的鏈表叫做靜態鏈表
- 數組元素都是由兩個數據域組成的,data和cur.
data:用來存放數據元素
cur:相當於單鏈表中的next,存放元素的後繼在數組中的下標,稱作遊標