数据结构-02线性表的笔记

线性表

  1. 相同数据类型
  2. 有限
  3. 序列

基础定义

使用c/c++通用的语法定义:

1. 顺序表:用数组实现

int A[MaxSize];		//定义顺序表,一次性开辟好空间。
int length = 0;		//顺序表的数据长度,使用时再修改长度。

特点:顺序存储可以根据下标快速访问元素;插入、删除要移动大量的数据、一次性开辟好全部空间等。

2. 链表:用结构体实现。

  • 单链表:只有一个指针:
typedef struct LNode{
   int data;				//数据项
   struct LNode* next;		//链表指针向后
}LNode;
  • 双链表:两个指针:
typedef struct DLNode{
   int data;				//数据项
   struct DLNode* next;		//链表指针向后
   struct DLNode* prior;		//链表指针向前
}DLNode;

链表的使用

单链表示意图:
在这里插入图片描述

//创建结点
LNode *L;
L=(LNode*)ma11oc(sizeof(LNode));
//同理创建ABCD结点后,用next指针进行连接。
A->next = B; 
B->next = C;
C->next = D;

单链表:
单链表的结构示意图以及判空条件
在这里插入图片描述
其中头结点是没有数据的节点,用来更方便地操作链表。
在这里插入图片描述

双链表的使用:
在这里插入图片描述
双链表的结构示意图以及判空条件:
在这里插入图片描述

循环链表

在这里插入图片描述
在这里插入图片描述

静态链表

typedef struct {
	int data;		//数据内容。
	int next;		//使用整形数据保存地址,相当于指针类型。 
}SLNode;

示意图如下:
在这里插入图片描述

链表的操作

插入删除操作

单链表:
插入操作:注意顺序
在这里插入图片描述

删除操作:使用free()函数:
在这里插入图片描述
注意事项:
在这里插入图片描述

双链表:
在这里插入图片描述
删除操作:
在这里插入图片描述

建表

顺序表建立:

int A[MaxSize];
int length;
int createlist(int A[]int &length){
    cin>>length;
    if (length > MaxSize)
        return 0

    forint i=0; i<length; ++i)
        cin>>A[i];
    return 1
}

链表的建立:(插入操作)

  1. 尾部插入法:
void createLinkListR(LNode *&head){
    head = (LNode*)malloc(sizeof(LNode));	//创建头结点
    head->next = NULL; 
    LNode *p = NULL, *r = head;//创建两个结点,p用来为新节点服务,r用来暂时保存前一个结点的指向
    int n;					   //数据结点个数
    cin>>n; 
    for (int i = 0; i < n; ++i){
        p = (LNode*)malloc(sizeof(lNode));	//创建结点
        p->next= NULL;		
        cin>>p->data;
        p->next = r->next;		//创建的结点进行连接,可略,用于链表中部插入结点
        r->next = p;			//
        r = p;					//r始终指向当前最后的结点
    }
}
  1. 头部插入法
void createLinkListH(LNode *&head){
    head = (LNode*)malloc(sizeof(LNode));	//创建头结点
    head->next = NULL; 
    LNode *p = NULL;//创建结点,p用来为新节点服务
    int n;					   //数据结点个数
    cin>>n; 
    for (int i = 0; i < n; ++i){
        p = (LNode*)malloc(sizeof(lNode));	//创建结点
        p->next= NULL;		
        cin>>p->data;
        p->next = head->next;		//创建的结点进行连接,可略,用于链表中部插入结点
        head->next = p;			
    }
}

!!!!!使用头部插入法的顺序结果应该是逆序哦。

应用例题:

键盘输入n个英文字母,输入格式为n、C1、C2、…、Cn,其中表示字母的个数。请编程以这些输入数据建立一个单链表,并要求将字母不重复的存入链表。

输入一个单词,扫描其在链表中是否岀现,如果岀现,就什么都不做;否则,根据这个单词构造结点插入链表中。

//头部插入发代码实现:
void createLinkListNoSameElem(LNode *&head){
    head = (LNode*)malloc(sizeof(LNode));	//创建头结点
    head->next = NULL; 
    LNode *p = NULL;//创建结点,p用来为新节点服务
    int n;					   //数据结点个数
    char ch;
    cin>>n; 
    for (int i = 0; i < n; ++i){
        cin>>ch;
        p = head->next;
        while(p != NULL){
        	if(p->data == ch)
        		break;
        	p = p->next;
        }
        
        if(p == NULL){
        	p = (LNode*)malloc(sizeof(lNode));	//创建结点
        	p->data = ch;		
        	p->next = head->next;
        	head->next = p;
        }
    }
}

表的逆置

  1. 顺序表(数组):
    在这里插入图片描述

在这里插入图片描述

//偶数奇数通用
for (int i = left, j = right; i < j; ++i, --j){
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}
  1. 链表的逆置:
    在这里插入图片描述
while(p->next !=q){
	t = p->next;
	p->next = t->next;
	t->next = q->next;
	q->next = t;
}

例题:

将一长度为n的数组的前端k(k<n)个元素逆序后移动到数组后端,要求原数组中数据不丢失;

void reverse(int a[], int left, int right, int k){
	int temp;
	for(int i = left, j = right, i < left + k && i < j; ++i, --j){
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
	}
}

将一长度为n的数组的前端k(k<n)个元素保持原序移动到数组后端,要求原数组中数据不丢失;
思路:把要交换的先逆置一下,再交换。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

void moveToEnd(int a[]; int n; int k){
	reverse(a, 0, k-1, k);
	reverse(a, 0, n-1, k);		
}

取最值

顺序表:

int max = a[0];
int maxIdx = 0;
for (int i = 0; i < n; ++i){
	if (max < a[i]){
		max = a[i];
		maxIdx = i;
	}
}

链表:

LNode *p, *q;
int max = head->next->data;
q = p = head->next;		//q用于结点的遍历的移动
while(p != NULL){
	if (max < p->data){
		max = p->data;
		q = p;
	}
	p = p->next;
}

例题:

双链表非空,由head指针指出,结点结构为{llink, data, rlink},请设计一个将结点数据域data值最大的那个结点(最大值结点只有一个)移动到链表最前边的算法,要求不得申请新结点空间。

首先双链表定义:

typedef struct DLNode{
	int data;				//数据项
	struct DLNode* llink;		//链表指针
	struct DLNode* rlink;		//链表指针
}DLNode;
void maxFirst(DLNode *head){
	DLNode *p = head->rlink, *q =p;
	int max = p->data;
//找最值
	while(p != NULL){
		if (max < p->data){
			max = p->data;
			q = p;
		}
		p = p->rlink;
	}
}
//删除
DLNode *l = q->llink, *r = q->rlink;
l->rlink = r;
if (r != NULL)
	r ->llink = l;
//插入最值结点
q->llink = head;
q->rlink = head->rlink;
head->rlink = q;
q->rlink->llink = q;

例题:

假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,如," loading”和" being"的存储映像如下图所示。
在这里插入图片描述
设st1和st2分别指向两个单词所在单链表的头结点,链表结点结构为{data,next},请设计一个时间上尽可能高效的算法,找岀由str1和str2所指向两个链表共同后缀的起始位置(如图中字符诟在结点的位置p)
要求
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++或JAVA语音描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度。

思路:用长度的差值入手破解。

1)分别求出str1和st2所指的两个链表的长度m和n
2)令指针p、q分别指向st1和st2的头结点,若m>=n,则使p指向链表中的第m-n+1个结点若m<n,则使q指向链表中的第n-m+1个结点;即使指针ρ和q所指的结点到表尾的长度相等
3)将指针p和q同步向后移动,并判断它们是否指向同一结点。若p和q指向同一结点,则该点即为所求的共同后缀的起始位置。

在这里插入图片描述

划分问题

· 枢轴
在这里插入图片描述

在这里插入图片描述

归并问题

(合成大西瓜)

  1. 把两个数组合并成一个,按照从小到大的顺序。
    用数组实现:
    在这里插入图片描述
void mergeArray(int a[], int m, int b[], int n, int c[]){
    int i = 0, j = 0;	//作为a、b的遍历的下标
    int k = 0;			//作为c的遍历下标
    while (i < m && j < n){
    //相同长度部分的合并
    if (a[i] <b[j])
        c[k++]=a[i++];//c[k]=a[i];k++;i++; 
    else 
    	c[k++]=b[j++];
    	
    //较长的数组的处理
	while (i < m)
    	c[k++]=a[i++]; 
	while (j < n)
    	c[k++]=b[j++];
	}
}
  1. 用链表的实现:
    在这里插入图片描述
void merge(LNode *A, LNode *B, LNode *&C){
    LNode *p = A->next;		//取A,B的头结点
    LNode *q = B->next;
    LNode *r;       //标记尾部位置的指针
    C = A;			//任意取一个头结点
    C->next = NULL;	//结点指针初始化
    free(B);
    r = C;
    //数据处理
    while(p != NULL &&q != NULL){
        if(p->data <= q->data){
            r->next = p;
            p = p->next;
            r = r->next;
        }
        else{
            r->next = q;
            q= q->next;
            r =r->next;
        }
	}
    if (p!=NULL)    r->next = p;
    if (q!=NULL)    r->next = q;
    
}

法2:逆序归并:
在这里插入图片描述
在这里插入图片描述

void merge(LNode *A, LNode *B, LNode *&C){
    LNode *p = A->next;		//取A,B的头结点
    LNode *q = B->next;
    LNode *s;       //标记尾部位置的指针
    C = A;			//任意取一个头结点
    C->next = NULL;	//结点指针初始化
    free(B);
    //r = C;
    //数据处理
    while(p != NULL && q != NULL){
        if(p->data <= q->data){
            s = p;
            p = p->next;
            s->next = C->next;
            C->next = s;
        }
        else{
            s = q;
            p = q->next;
            s->next = C->next;
            C->next = s;
        }
	}
    	while(p!=NULL){
       		s = p;
            p = p->next;
            s->next = C->next;
            C->next = s;
        }
        while(q!=NULL){
            s = q;
            p = q->next;
            s->next = C->next;
            C->next = s;
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值