1.顺序表示
1.静态分配
- 定义
//线性表数组静态分配
typedef struct {
ElemType data[MaxSize];//顺序表 元素
int length;//顺序表的当前长度
}SqList;//顺序,表的类型定义
main函数调用
SqList L = { {2, 1,6,4,5,4,4,4,3, 4 ,7} ,11 };
2.动态分配
//线性表数组动态分配
typedef struct {
ElemType* data;//指示动态分配数组的指针
int MaxSize2, length; //数组的最大容量和当前个数
}SeqList;//动态分配数组顺序衰的类型定义
main函数
/*动态分配数组*/
SeqList L;
L.data = (ElemType*)malloc(sizeof(ElemType) * InitSize);
3.相关函数操作
//链表初始化
SqList Listinit() {
SqList L;
L.length = 0;
//printf("%d创建成功\n", L.length);
return L;
}
//指定位置插入元素
ElemType Listinsert(SqList *L, int i, ElemType e){
if (i < 1 || i > L->length + 1)//判断i的范围是否有效
return false;
if (L->length >= MaxSize)//当前存储空间己满 不能插入
return false;
for (int j = L->length; j >= i;j--) //将第i个元素及之后的元素后移
L->data[j] = L->data[j - 1];
L->data[i - 1] = e;//在位i处放入e
L->length++;//线性表长度加1
return true;
}//Listinsert
//删除元素
int listDelete(SqList *L, int i, Elemtype *e) {
if (i<1 || i>L->length)//判断i的范围是否有效
return false;
e = L->data[i - 1];//将被删除的元素赋值给e
for (int j = i;j < L->length;j++) //将第i个位置后的元素前移
L->data[j - 1] = L->data[j];
L->length--;//线性表长度减1
return true;
}//ListDelete
//链表遍历
void output(SqList *L) {
for (int i = 0;i < L->length;i++)
printf("结果为:%d\n",L->data[i]);
}
4.相关代码:
现成代码链接:
线性表顺序表示代码:
#include<stdio.h>
#include<malloc.h>
#define MaxSize 50//定义线性袤的最大长度
#define ElemType int//定义类型
#define Elemtype int*//定义指针类型
#define InitSize 100//表长度的初始定义
#define false 0
#define true 1
//线性表数组静态分配
typedef struct {
ElemType data[MaxSize];//顺序表 元素
int length;//顺序表的当前长度
}SqList;//顺序,表的类型定义
//线性表数组动态分配
typedef struct {
ElemType* data;//指示动态分配数组的指针
int MaxSize2, length; //数组的最大容量和当前个数
}SeqList;//动态分配数组顺序衰的类型定义
void main() {
//声明
//函数声明
SqList Listinit();//链表初始化
ElemType Listinsert(SqList *L, int i, ElemType e);//插入元素
void output(SqList *L);//遍历所有数据
//习题声明
/*ElemType deiMin(SqList L, ElemType e);
void delSelected(SqList &L, ElemType e);*/
SqList antiList(SqList * L);
SqList delSelected(SqList * L, ElemType e);
SqList delSelectedRangeOfSorted(SqList * L, int min, int max);
SqList delSelectedRangeOfUnsorted(SqList * L, int min, int max);
SqList delReplicated(SqList * L);
SqList* plusSorted(SqList * L1, SqList * L2);
SqList tranLocate(SqList * L, int n);
SqList tranLocate_2(SqList * L, int n);
SqList Reverse(SqList * L, int start, int end);
SqList findOrInsert(SqList * L, ElemType e);
ElemType findMid(SqList * L1, SqList * L2);
ElemType findMainData(SqList * L);
int findUnSeeMin(SqList * L);
/*动态分配数组*/
//SeqList L;
//L.data = (ElemType*)malloc(sizeof(ElemType) * InitSize);
///*Listinsert*/
/*SqList L = Listinit();
Listinsert(&L, 1, 5);
output(&L);*/
/**/
/**** 题目测试*** */
///*1.deiMin*/
/*SqList L = { { 12,15, 8, 6, 9, 45, 13 } ,7};
ElemType min = deiMin(&L);
printf("min = %d\n",min);*/
/**/
///*2.antiList*/
/*SqList L = { { 12,15, 8, 6, 9, 45, 13 ,78} ,8 };
L = antiList(&L);
output(&L);*/
/**/
/*3delSelected*/
/*SqList L = { { 12,15, 8, 6, 9, 45, 13 ,8 ,8 ,9} ,10 };
L = delSelected(&L,8);
output(&L);*/
/*4delSelectedRangeOfSorted*/
/*SqList L = { { 1,2, 3, 4, 5, 6, 7 ,8 ,9} ,9 };
L = delSelectedRangeOfSorted(&L,2,5);
output(&L);*/
/*5delSelectedRangeOfUnsorted*/
/*SqList L = { { 5,2, 8, 4, 1, 6, 9 ,3 ,7} ,9 };
L = delSelectedRangeOfUnsorted(&L,2,5);
output(&L);*/
/*6delReplicated*/
/*SqList L = { { 1,2,2, 4, 5, 6, 6 ,6 ,7} ,9 };
L = delReplicated(&L);
output(&L);*/
/*8plusSorted*/
/*SqList L;
SqList L1 = { { 0,1,2, 4, 5 ,7,12} ,7 };
SqList L2 = { { 3,5,8,9,10,11} ,6 };
L = *plusSorted(&L1, &L2);
output(&L);*/
/*8plusSorted*/
/*SqList L;
SqList L1 = { { 0,1,2, 4, 5 ,7,12} ,7 };
SqList L2 = { { 3,5,8,9,10,11} ,6 };
L = *plusSorted(&L1, &L2);
output(&L);*/
/*9.1tranLocate*/
/*SqList L = { { 1,2,3, 4, 5 ,6,7,8,9,10,11} ,11 };
L = tranLocate(&L,5);
output(&L);*/
/*9.1tranLocate_2*/
/*SqList L = { { 1,2,3, 4, 5 ,6,7,8,9,10,11} ,11 };
L = tranLocate_2(&L, 5);
output(&L);*/
/*10findOrInsert*/
//SqList L = { { 1,2,3, 4, 5 ,6,7,9,10,11} ,10 };
/*SqList L = { { 1,2,3, 4 ,6,7,9,10,11} ,9 };
L = findOrInsert(&L, 5);
output(&L);*/
/*11tranLocate_2*/
/*SqList L = { { 1,2,3, 4 ,6,7,9,10,11} ,9 };
L = tranLocate_2(&L, 5);
output(&L);*/
/*12findMid*/
/*ElemType mid;
SqList L1 = { { 1,3, 4 ,7,10} ,5 };
SqList L2 = { { 0,2,3,6,9,11} ,6 };
mid = findMid(&L1, &L2);
printf("the mid is:%d\n", mid);*/
/*13findMainData*/
/*ElemType mad;
SqList L = { {4, 1,2,4,5,4,4,4,3, 4 ,7} ,11 };
mad = findMainData(&L);
if (mad == -1)
printf("没有找到\n");
else
printf("the mainData is:%d\n", mad);*/
/*13findUnSeeMin*/
ElemType min;
SqList L = { {2, 1,6,4,5,4,4,4,3, 4 ,7} ,11 };
min = findUnSeeMin(&L);
printf("the unSeeMinData is:%d\n", min);
}//main
//链表初始化
SqList Listinit() {
SqList L;
L.length = 0;
//printf("%d创建成功\n", L.length);
return L;
}
//链表遍历
void output(SqList *L) {
for (int i = 0;i < L->length;i++)
printf("结果为:%d\n",L->data[i]);
}
//指定位置插入元素
ElemType Listinsert(SqList *L, int i, ElemType e){
if (i < 1 || i > L->length + 1)//判断i的范围是否有效
return false;
if (L->length >= MaxSize)//当前存储空间己满 不能插入
return false;
for (int j = L->length; j >= i;j--) //将第i个元素及之后的元素后移
L->data[j] = L->data[j - 1];
L->data[i - 1] = e;//在位i处放入e
L->length++;//线性表长度加1
return true;
}//Listinsert
//删除元素
int listDelete(SqList *L, int i, Elemtype *e) {
if (i<1 || i>L->length)//判断i的范围是否有效
return false;
e = L->data[i - 1];//将被删除的元素赋值给e
for (int j = i;j < L->length;j++) //将第i个位置后的元素前移
L->data[j - 1] = L->data[j];
L->length--;//线性表长度减1
return true;
}//ListDelete
//习题函数
//一
ElemType deiMin(SqList *L){
//删除并返回最小值
/*设计思想:假定第一个元素是最小值,通过循环比较,若出现更小的,将其赋给那个变量,然后再将最后一个值赋给要删除的位置
**/
ElemType min = L->data[0], temp;
int i, locate;
if (L->length < 1)
return false;
for (i = 0;i < L->length;i++) {//找到最小值,并记住其下标
if (min > L->data[i])
min = L->data[i];
locate = i;
}//for
temp = L->data[locate];
L->data[locate] = L->data[L->length - 1];//将最后一个值进行覆盖
L->length--;//链表长度减一
return min;
}//deiMin
//二
SqList antiList(SqList *L){
//数据逆置
/*设计思想:通过循环,将首尾元素对调,并返回新顺序表
**/
ElemType temp;
int i;
for (i = 0;i < L->length / 2;i++){
temp = L->data[(L->length - 1) - i];
L->data[(L->length - 1) - i] = L->data[i];
L->data[i] = temp;
}//for
return *L;
}//antiList
//3
SqList delSelected(SqList *L, ElemType e){
//删除顺序表指定所有数据
/*设计思想:建立一个新数组,再通过循环先找到所有要删除的下标,然后存入新数组,然后通过比较依次将后面不是指定数据
* 的元素插到新数组中的下标内,最后更改链表长度
**/
int* array;
array = (ElemType*)calloc(L->length, sizeof(ElemType*));//建立一个与原数组同样大小的函数,存储相同数的下标
int i,j=0;
for (i = 0;i < L->length;i++) {//找到所有要删除的下标
if (L->data[i] == e) {
array[j] = i;
j++;//相同数的数量,位序
}//if
}//for
int sameNum = j;//相同元素的数目
j = 0;
for (i = L->length - 1;i > 0 ;i--) {//将最后的元素调到需要删除元素的位置
if (L->data[i] != e ) {//保证后面元素不是要被删除的元素
L->data[array[j]] = L->data[i];
j++;
}//if
if (j >= sameNum - 1)
break;//跳出循环,否则,因array[sameNum]=0,故第一个数值会改变为第二个数值,且浪费时间
}//for
L->length = L->length - sameNum;
/*设计思想:用k记录不等于e的元素个数,并扫描边统计k,并将不等于e的元素向前移k个位置,最后修改长度
* */
//int k = 0,i;
//for (i = 0;i < L->length;i++) {
// if (L->data[i] != e) {
// L->data[k] = L->data[i];
// k++;
// }//if
//}//for
//L->length = k;
return *L;
}//delSel
//4
SqList delSelectedRangeOfSorted(SqList* L,int min,int max) {
//有序表中删除指定范围的数据
/*设计思想:通过循环将第一个元素的下表找出,并统计范围内数据的数量,然后直接将后面不在范围内的数据前移
**/
//if (L->length < 1 || min > max) {
// printf("链表为空或者范围有误\n");
// return *L;
//}//if
//int i,rangeNum = 0,locate;//指定范围的数据个数,位序
//for (i = 0;i < L->length;i++) {
// if (L->data[i] >= min && L->data[i] <= max) {//注意边缘范围也要算上
// rangeNum++;
// if (rangeNum == 1)
// locate = i;//起始位置,下标
// }//if
//}//for
//if (locate + rangeNum < L->length)//只有当后面还有数据没被删除时,需要前移=====有序表的优点
// for (i = locate ;i < L->length;i++) //将范围外数据前移
// L->data[i] = L->data[i + rangeNum];
//L->length = L->length - rangeNum;//更改链表长度
/*设计思想:先找到值大于等于min的元素,然后找到大于max的第一个元素,再将其前移即可
* */
if (L->length < 1 || min > max) {
printf("链表为空或者范围有误\n");
return *L;
}//if
int i,j;//指定范围的数据个数,位序
for (i = 0;i < L->length && L->data[i] < min;i++) //找到值大于等于min的第一个元素
if (i >= L->length) //所有值都小于min
L->length = 0;
for (j = i;j < L->length && L->data[j] <= max;j++);//找到值小于max的第一个元素
for (;j < L->length;i++, j++)
L->data[i] = L->data[j];
L->length = i;
return *L;
}//delSelectedRange
//5
SqList delSelectedRangeOfUnsorted(SqList * L, int min, int max){
//无序表中删除指定范围的数据,类似第三题
/*设计思想:通过建立一个新数组,将在其范围的数据下标存储起来,然后通过从链表最后数据开始,比较其是否在该范围内,
*若不在,直接将数据存在下标数组的第一个位置,依次类推,最后更改链表长度
**/
//if (L->length < 1 || min > max) {
// printf("链表为空或者范围有误\n");
// return *L;
//}//if
//int* array;
//array = (ElemType*)calloc(L->length, sizeof(ElemType*));//建立一个与原数组同样大小的函数,存储相同数的下标
//int i, j = 0;
//for (i = 0;i < L->length;i++) {//找到所有要删除的下标
// if (L->data[i] >= min && L->data[i] <= max) {
// array[j] = i;
// j++;//相同数的数量,位序
// }//if
//}//for
//int samenum = j;//相同元素的数目
//for (i = L->length - 1,j = 0 ;i > 0 ;i--) {//将最后的元素调到需要删除元素的位置
// if (L->data[i] < min || L->data[i] > max) {//保证后面元素不在范围内
// L->data[array[j]] = L->data[i];
// j++;
// }
// if (j == samenum)
// break;
//}//for
//L->length = L->length - samenum;
/*设计思想:从前向后扫描顺序表,用k记录值不在s到t的个数。若不在范围,则前移k个位置,否则k++,最后修改长度
*
**/
if (L->length == 0 || min >= max) {
return *L;
}//if
int i, k = 0;
for (i = 0;i < L->length;i++) {
if (L->data[i] < min || L->data[i] > max) {
L->data[k] = L->data[i];
k++;
}//if
}//for
L->length = k;
return *L;
}//delSelectedRangeOfUnsorted
//6
SqList delReplicated(SqList* L) {
//有序表删除重复数据
/*设计思想:通过循环将重复出现的元素跳过,最后修改长度
* */
if (L->length == 0) {
return *L;
}//if
int i, j;
for (i = 0, j = 1;j < L->length;j++) {
if (L->data[i] != L->data[j]) {//若出现的不是重复的元素
L->data[++i] = L->data[j];//
}//if
}//for
L->length = i + 1;
return *L;
}//delReplicated
//7
SqList* plusSorted(SqList* L1, SqList* L2) {
//将两个有序表结合为一个新有序,并返回新表
/*设计思想:建立一个长度为两个链表长度总和的新链表,通过比较两个链表的大小,将小的一个插入新链表
**/
//SqList L;
//L.length = L1->length + L2->length;
//int i,j = 0,k = 0;
//for (i = 0;i < L.length;i++) {
// if (j < L1->length && k < L2->length) {
// if (L1->data[j] <= L2->data[k]) {
// L.data[i] = L1->data[j];
// j++;
// }//if
// else if (L1->data[j] > L2->data[k]) {
// L.data[i] = L2->data[k];
// k++;
// }//if
// }//if
// else {
// if (k == L2->length) {
// L.data[i] = L1->data[j];
// j++;
// }//if
// else if (j == L1->length) {
// L.data[i] = L2->data[k];
// k++;
// }//if
// }//else
//}//for
/*设计思想:按顺序将两表较小元素存入新表,然后将还有剩余的表的元素再插入
* */
SqList L;
if (L1->length + L2->length > MaxSize) {
return &L;
}//if
int i = 0, j = 0, k = 0;
while (i < L1->length && j < L2->length) {
if (L1->data[i] <= L2->data[j])
L.data[k++] = L1->data[i++];
else
L.data[k++] = L2->data[j++];
}//while
while (i < L1->length)
L.data[k++] = L1->data[i++];
while (j < L2->length)
L.data[k++] = L2->data[j++];
L.length = k;
return &L;
}//plusSorted
//8.1
SqList tranLocate(SqList *L,int n) {
//将一个数组中的两个线性表的位置互换,n为两链表的交界处(位序)
/*设计思想:建立一个数组,将后半部分先存入数组,再将后半部分前移,最后将数组元素插入顺序表
**/
ElemType* array;
array = (ElemType*)calloc(n, sizeof(ElemType*));
int i,j = 0;
for (i = 0;i < n;i++) {//将前部分存入数组
array[j] = L->data[i];
j++;
}//for
int k;
for (k = 0;k < L->length && i < L->length;k++) {//将后半部分前移
L->data[k] = L->data[i];
i++;
}//for
for (i = 0;k < L->length;k++) {//将数组元素插入表后
L->data[k] = array[i];
i++;
}//for
return *L;
}//tranLocate
//8.2
SqList tranLocate_2(SqList* L, int n) {
/*设计思想:先将所有元素逆置,再将前L->length-n个元素逆置,最后将后n个元素逆置
* */
*L = Reverse(L, 0, L->length);
*L = Reverse(L, 0, L->length - n);
*L = Reverse(L, L->length - n, L->length);
return *L;
}//tranLocate_2
SqList Reverse(SqList* L, int start, int end) {
//将顺序表指定位置范围的元素逆置
ElemType temp;
int i;
for (i = start;i < ((end - start) / 2)+start;i++) {
temp = L->data[(end - 1) - i + start];
L->data[(end- 1) - i + start] = L->data[i];
L->data[i] = temp;
}//for
return *L;
}//Reverse
//9
SqList findOrInsert(SqList* L, ElemType e) {
//在有序递增表中找数,找到与后面的元素交换位置,找不到插入表中使其仍然有序,要求最少时间
/*设计思想:通过对半法:先找中间的元素,大于找前半,小于找后半;依次类推,找到后保存其下表,在根据下标进行选择,
* 若存在,直接通过下标对其后一位进行对调;若不存在,则将数组数据后移后,再进行插入
**/
//int locate = -1, flag = 1, top = L->length, bottom = 0;//下标的上下限,下标
//while (flag) {
// if (top <= bottom)
// flag = 0;
// if (L->data[(top + bottom) / 2] > e) {//在前半
// top = ((top + bottom) / 2) - 1;//取中间的坐标
// }//if
// else if (L->data[(top + bottom) / 2] < e) {//在后半
// bottom = ((top + bottom) / 2) + 1;
// }//else if
// else {//刚刚好
// locate = L->data[(top + bottom) / 2];//记录找到元素的位序
// }//else
//}//while
//printf("%d\n",locate);
插入或换
//if (locate != -1 && L->data[locate - 1] != e) {//未找到时
// L->length++;
// int i;
// for (i = L->length - 1;i < locate;i++)
// L->data[i] = L->data[i - 1];
// L->data[locate + 1] = e;
//}//if
//else//找到后
// L->data[locate] = e;
ElemType temp;
int top = L->length - 1, bottom = 0,mid;//下标的上下限,下标
while (bottom <= top) {
mid = (bottom + top) / 2;//中间位置
if (L->data[mid] == e)//找到e时退出
break;
else if (L->data[mid] < e)//右半部分查找
bottom = mid + 1;
else//左半部分查找
top = mid - 1;
}//while
if (L->data[mid] == e) {//最后一个元素与e相等,交换找到的后一个元素
temp = L->data[mid];
L->data[mid] = L->data[mid + 1];
L->data[mid + 1] = temp;
}//if
if (bottom > top) {//查找失败。插入数据
L->length++;//修改长度
int i;
for (i = L->length - 1;i > top;i--)
L->data[i + 1] = L->data[i];
L->data[i + 1] = e;
}//if
return *L;
}
//10同tranLocate_2,将数组的n位循环左移n位
//11
ElemType findMid(SqList* L1, SqList* L2) {
//将两个等长升序的数组的中位数找到并返回,二选一取左边位置
/*设计思想:按顺序将两表较小元素存入新表,然后将还有剩余的表的元素再插入
* */
SqList L;
if (L1->length + L2->length > MaxSize) {
return &L;
}//if
int i = 0, j = 0, k = 0;
while (i < L1->length && j < L2->length) {
if (L1->data[i] <= L2->data[j])
L.data[k++] = L1->data[i++];
else
L.data[k++] = L2->data[j++];
}//while
while (i < L1->length)
L.data[k++] = L1->data[i++];
while (j < L2->length)
L.data[k++] = L2->data[j++];
L.length = k;
return L.data[(L.length-1) / 2];
}//findMedel
//12
ElemType findMainData(SqList *L){
//找主元素,主元素就是在一个数组中最多的哪个元素,其个数要大于(不能等于)总元素的一半,找到返回该元素,否则返回-1
/*设计思想:通过一个含有两个参数:数据、数量的二维数组(可以用结构体比较好),先统计所有数据的数量,再根据其数量是否有
* 大于一半的,有返回数据,没有返回-1
* */
//ElemType array[10][2];//设置一个静态数组============数组长度有浪费
//int i,j,arrayLength = 0,flag = 0;//二维数组长度
//for (i = 0;i < L->length;i++) {
// if (i == 0) {
// array[i][0] = L->data[i];
// array[i][1] = 1;
// arrayLength++;
// }//if
// else {
// flag = 0;
// for (j = 0;j < arrayLength;j++) {//已经出现过时
// if (L->data[i] == array[j][0]) {
// array[j][1]++;
// flag = 1;
// }//if
// }//for
// if (flag == 1) {
// array[j][0] = L->data[i];//否则存入数组
// array[j][1] = 1;
// arrayLength++;
// }
// }//else
//}//for
//int locate = 0;
//for (i = 1;i < arrayLength;i++) {//找二维数组数量最大哪个下标
// if (array[i][1] > array[locate][1])
// locate = i;
//}//for
//if (array[locate][1] > L->length / 2)//比较其数量是否满足要求
// return array[locate][0];
//else
// return -1;
/*设计思想:扫描前半部分元素,然后统计前半部分的每个元素位置之后的元素数量,只要有大于一半的元素,直接跳出循环,否则
* 就不存在主元素
* */
//int i, j, sum;
//for (i = 0;i < L->length / 2;i++) {//遍历前半部分元素
// sum = 0;
// for (j = i;j < L->length;j++) {//统计元素开始到末尾的所有元素个数
// if (L->data[i] == L->data[j])
// sum++;
// }
// if(sum > L->length/2)//找到主元素时,直接返回
// return L->data[i];
//}
//return -1;
/*设计思想:扫描顺序表,标记一个可能的主元素may,然后重新计数,确认是否为主元素,1.选取候选主元素,依次扫描整个表,
* 将第一个遇到的整数保存到may中,,记录其出现次数为1;若遇到下一个整数仍为may,则计数加1,否则减1;当计数减为0时,将
* 遇到的下一个正数保存到may中,计数重新记为1,开始新一轮计数,即从当前位置重复上述过程,直到完全扫描完全部顺序表;
* 2.判断may中元素是否为真正的主元素,再次扫描该数组,统计may中元素出现的次数,若大于N/2则为主元素,否则不存在
* */
int i, may, count = 0;
may = L->data[0];//设置L->data[0]为候选主元素
for (i = 1;i < L->length;i++) {//查找候选主元素
if (L->data[i] == may)
count++;//对顺序表的候选主元素计数
else
if (count > 0)//处理不是候选主元素的情况
count--;
else {//更换候选主元素
may = L->data[i];
count = 1;
}//else
}//for
if (count > 0)
for (i = count;i < L->length;i++)//统计候选主元素的实际出现次数
if (L->data[i] == may)
count++;
if (count > L->length / 2)//确认候选主元素
return may;
else//不存在主元素
return -1;
}//findMainData
//13
int findUnSeeMin(SqList* L) {
//找出给定数组中未出现的最小正整数(由1开始,0既不是正数也不是负数)
/*设计思想:先将其排好序,找到数组最小元素位置,通常为1,然后通过由1开始的递增,进行循环比较,首次未出现的就是
**/
int i,j;
ElemType temp;
for (i = 0;i < L->length;i++) {//冒泡排序法
for (j = i + 1;j < L->length;j++) {
if (L->data[i] > L->data[j]) {//由小到大排序
temp = L->data[i];//将两个数交换位置
L->data[i] = L->data[j];
L->data[j] = temp;
}//if
}//for
}//for
for (i = 0, j = 0;j < L->length;j++) {
if (L->data[j+1] != L->data[j]) {//将重复出现的元素删除
L->data[i++] = L->data[j];//
}//if
}//for
L->length = i;
j = 1;
for (i = 0;i < L->data[L->length-1];i++) {//遍历到数据为1的地方
if (L->data[i] > 0 ) {
if (L->data[i] != j) {//无论在哪个位置,j都是最小正整数
return j;
}//if
j++;
}//if
}//for
return j;
}//findUnSeeMin
2.链式表示
2.0头指针
头结点优点:
①由于第一个数据结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。
②无论链表是否为空,其头指针都指向头结点非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就得到了统一。
注意:头结点和头指针区分:不管带不带头结点,头指针始终指向链表的第一个结点,而头结点是带头结点的链表中的第一个结点,结点内通常不存储信息。
2.1单链表
1.定义
2.操作
2.2双链表
1.定义
2.操作
2.3循环链表
1.定义
2.操作
3.二者区别
3.1存取方式
顺序表可以顺序存取,也可以随机存取,链表只能从表头顺序存取元素。例如在第i个位置上执行存或取的操作,顺序表仅需一次访 问,而链表则需要从表头开始依次访问i次。
3.2逻辑和物理结构
采用顺序存储时,逻辑上相邻的元素 ,对应的物理存储位置也相邻。 采用链式存储 ,逻上相邻的元素 ,物理存储位置则不一定相邻,对应的逻辑关系是通过指针链接来表示的。
3.3查找、插入和删除操作
对于按值查找,顺序表无序时 两者的时间复杂度均为 O(n);顺序表有序时,可采用折半查找,此时的时间复杂度 O(log2n).
对于按序号查找,顺序表支持随机访问,时间复杂度仅为 O(1),而链表的平均时间复杂度为O(n)。顺序表的插入、删除操作,平均需要移动半个表长的元素。链表的插入、删除操作,只需修改相关结点的指针域即可。由于链表的每个结点都带有指针域,故而存储密度不够大
3.4空间分配
顺序存储在静态存储分配情形下,一旦存储空间装满就不能扩充,若再加入新元素,则会出现内存溢出,因此需要预先分配足够大的存储。预先分配过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出。动态存储分配虽然存储空间可以扩充,但需要移动大量元素,导致操效率降低,而且若内存中没有更大块的连续存储空间 ,则会导致分配失败。链式存储的结点空间只在需要时申请分配,只要内存有空间就可以分配,操作灵活、高效。